package me.zhengjie.minbearwcs.serivce.mission.generate.shifting;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.minbearwcs.dao.mission.inf.WcsMissionDao;
import me.zhengjie.minbearwcs.dao.shifting.inf.ShiftingTaskRecordDao;
import me.zhengjie.minbearwcs.dao.stock.inf.PalletDao;
import me.zhengjie.minbearwcs.dao.storage.inf.SmallStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.StorageDao;
import me.zhengjie.minbearwcs.entity.DTO.transfer.Tuple;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.WcsMission;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.status.ShiftingMissionStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.type.MissionType;
import me.zhengjie.minbearwcs.entity.PO.wcs.shifting.ShiftingTaskRecord;
import me.zhengjie.minbearwcs.entity.PO.wcs.shifting.status.ShiftingRecordStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.stock.Pallet;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.SmallStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.type.StorageType;
import me.zhengjie.minbearwcs.serivce.mission.generate.MissionGenerator;
import me.zhengjie.minbearwcs.serivce.mission.generate.type.MissionGenType;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor5Or6.ShiftingStorage5Or6FloorLocker;
import me.zhengjie.minbearwcs.utils.ContentPool;
import me.zhengjie.minbearwcs.utils.IdWorker;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class ShiftingMissionGenerator implements MissionGenerator<String> {

    private final SmallStorageDao smallStorageDao;
    private final ShiftingStorage5Or6FloorLocker shiftingStorage5Or6FloorLocker;
    private final PalletDao palletDao;
    private final IdWorker idWorker;
    private final ShiftingTaskRecordDao shiftingTaskRecordDao;
    private final WcsMissionDao wcsMissionDao;
    private final StorageDao storageDao;


    @Override
    public MissionGenType type() {
        return MissionGenType.SHIFTING;
    }

    @Override
    @Transactional
    public Tuple<String> generate(Object source) {
        String shiftPalletCode = (String) source;

        SmallStorage shiftingSmallStorage = smallStorageDao.selectByPallet(shiftPalletCode);

        if (shiftingSmallStorage == null) {
            return Tuple.tuple("该栈板不在储位，移库失败", false);
        }

        if (shiftingSmallStorage.getOutboundFreezePallet() != null || shiftingSmallStorage.getInboundFreezePallet() != null) {
            return Tuple.tuple("该栈板正在任务中，移库失败", false);
        }


        StorageType storageType = storageDao.selectStorageTypeBySmallStorage(shiftingSmallStorage.getSmallStorageCode());

        if (StorageType.STORAGE_AREA_5F != storageType && StorageType.STORAGE_AREA_6F != storageType) {
            return Tuple.tuple("该栈板不属于库区，不能移库", false);
        }

        List<SmallStorage> smallStorageList = smallStorageDao.selectSmallStorageByMediunStorage(shiftingSmallStorage.getMediumStorageCode());


        // 判断能否出去
        boolean enterCanOut = false;
        long enterCount = smallStorageList.stream()
                .filter(a -> a.getIsEntrance() == ContentPool.STORAGE_IS_ENTER)
                .count();

        if (enterCount == 1) {

            SmallStorage smallStorage = smallStorageList.get(0);
            if (smallStorage.getIsEntrance() == ContentPool.STORAGE_IS_ENTER) {
                enterCanOut = judgeCanOutFrontToBack(shiftingSmallStorage, smallStorageList);
            } else {
                enterCanOut = judgeCanOutBackToFront(shiftingSmallStorage, smallStorageList);
            }


        } else if (enterCount == 2) {
            enterCanOut = judgeCanOutBackToFront(shiftingSmallStorage, smallStorageList);
            if (enterCanOut == false) {
                enterCanOut = judgeCanOutFrontToBack(shiftingSmallStorage, smallStorageList);
            }
        } else {
            return Tuple.tuple("该储位没有出口，请检查", false);
        }


        if (!enterCanOut) {
            return Tuple.tuple("栈板所处中储位出口被堵，请先移库靠近出口货物", false);
        }


        Pallet pallet = palletDao.selectByPalletCode(shiftPalletCode);
        Tuple<String> lockStorage = shiftingStorage5Or6FloorLocker.lockInStorage(
                pallet.getMaterialCode(),
                pallet.getInboundOrderCode(),
                pallet.getBatchCode(),
                shiftPalletCode,
                shiftingSmallStorage.getMediumStorageCode()
        );

        if (!lockStorage.success) {
            return Tuple.tuple("没找到能移库的储位", false);
        }

        shiftingStorage5Or6FloorLocker.lockOutStorage(shiftingSmallStorage.getSmallStorageCode(), shiftPalletCode);

        String endPoint = lockStorage.value;

        String recordId = "Shifting_Record_" + idWorker.nextId();
        ShiftingTaskRecord shiftingTaskRecord = new ShiftingTaskRecord(null, recordId, shiftPalletCode, ShiftingRecordStatus.INIT,
                shiftingSmallStorage.getSmallStorageCode(), endPoint, LocalDateTime.now(), null);

        shiftingTaskRecordDao.insert(shiftingTaskRecord);


        String missionId = "Task_Shifting_" + idWorker.nextId();
        WcsMission mission = new WcsMission(null, missionId, recordId, MissionType.SHIFTING.name(),
                ShiftingMissionStatus.WAIT_FOR_DISPATCH.name(), LocalDateTime.now(), null, null,
                1, recordId);
        wcsMissionDao.insert(mission);
        log.info("栈板 {} ，移库记录 {} ，移库wcs任务 {} 生成成功",
                shiftPalletCode, recordId, missionId);

        return Tuple.tuple("移库任务生成成功", true);
    }

    private boolean judgeCanOutFrontToBack(SmallStorage shiftingSmallStorage, List<SmallStorage> smallStorageList) {
        boolean oneEnterCanOut = true;
        for (int i = 0; i < smallStorageList.size(); i++) {
            SmallStorage tempStorage = smallStorageList.get(i);
            if (shiftingSmallStorage.getSmallStorageCode().equals(tempStorage.getSmallStorageCode())) {
                break;
            }

            if (tempStorage.getOutboundFreezePallet() != null) continue;

            if (tempStorage.getPalletCode() != null || tempStorage.getInboundFreezePallet() != null) {
                oneEnterCanOut &= false;
            }
        }
        return oneEnterCanOut;
    }

    private boolean judgeCanOutBackToFront(SmallStorage shiftingSmallStorage, List<SmallStorage> smallStorageList) {
        boolean oneEnterCanOut = true;
        for (int j = smallStorageList.size() - 1; j >= 0; j--) {
            SmallStorage tempStorage = smallStorageList.get(j);
            if (shiftingSmallStorage.getSmallStorageCode().equals(tempStorage.getSmallStorageCode())) {
                break;
            }

            if (tempStorage.getOutboundFreezePallet() != null) continue;

            if (tempStorage.getPalletCode() != null || tempStorage.getInboundFreezePallet() != null) {
                oneEnterCanOut &= false;
            }
        }
        return oneEnterCanOut;
    }
}
